const express = require('express');

const { Op } = require("sequelize");

const Student = require('../models/Student.js');
const Course = require('../models/Course.js');

require('../models/association.js');


const router = express.Router();

// GET `/student/sign/in` 打开登录页面
router.get('/student/sign/in',(req,resp)=>{
    resp.render('student/sign-in',{ tip: req.session.tip } );
    delete req.session.tip ;
});

// POST `/student/sign/in` 处理登录操作
router.post('/student/sign/in',(req,resp)=>{
    let { name } = req.body ;
    Student.findOne({
        where: {
            name /* `name` 是 `name: name` 的缩写 */
        }
    }).then( stu => {
        if( stu ) {
            // 将学生信息保存到会话中
            req.session.student = stu.dataValues ;
            resp.redirect( '/student/choose');
            return;
        }
        req.session.tip = { value: name , message: '姓名不存在' }
        resp.redirect('/student/sign/in');
    });
});

router.get('/student/sign/out',(req,resp)=>{
    req.session.tip = { message: '已退出登录' }
    resp.redirect('/student/sign/in');
});

// GET `/student/choose` 显示课程列表，以便于让学生选课
router.get('/student/choose',(req,resp)=>{

    // 从 会话 中获取已经登录的学生
    const stu = req.session.student;

    // 若学生未登录则重定向到登录页面
    if( !stu ) {
        req.session.tip = { message: '登录后才能选课' }
        resp.redirect('/student/sign/in');
        return;
    }

    // 查询所有课程
    Course.findAll().then( courses => {
        let arr = courses.map( c => c.dataValues );
        return arr ;
    }).then( courses => {

        // 返回一个以给定值解析后的Promise 对象
        let promise1 = Promise.resolve( courses );
        
        // 查询已登录学生的所有信息(包含该学生选择的课程信息)
        let promise2 = Student.findByPk( stu.id , {
            include: {
                model: Course,
                // 指定将来在 Student实例中所包含的 Course数组的名称
                // 这里通过 `as` 指定的别名必须跟 belongsToMany 中所指定的别名相同
                as: 'courses',
            }
        });

        // Promise.all 会返回一个新的 Promise实例
        let promise3 = Promise.all( [ promise1 , promise2 ]);
        return promise3 ;
    }).then( values => {
        // 获得上一步的 Promise.all 参数对应的数组中第一个 Promise 的返回结果
        const allCourses = values[0];
        // 获得上一步的 Promise.all 参数对应的数组中第二个 Promise 的返回结果
        let student = values[1];
        // 获得当前已登录学生所选择的所有课程
        let choiceList = student.courses;
        choiceList = choiceList.map( c => {
            let x = c.dataValues;
            delete x.Score ;
            return x ;
        });
        
        // 进一步处理 allCourses 数组
        allCourses.forEach( course => {
            // 用 some 函数的参数来测试 choiceList 是否包含 course
            let result = choiceList.some( choice => choice.id == course.id );
            // 将 测试结果 保存到 course 对象的 checked 属性中
            course.checked = result ;
        });

        return allCourses ;
    }).then( courses => {
        let locales = {
            // `courses` 是 `courses: courses` 的缩写
            courses , 
            // 将已经登录学生添加到模板局部变量
            student: stu ,
        }
        resp.render( 'student/choose' , locales );
    }).catch( reason => {
        resp.render( 'student/choose' , { tip : { message: reason } } );
    });
});

// POST `/student/choose` 显示课程列表，以便于让学生选课
router.post('/student/choose',(req,resp)=>{
    // 从会话中获取已登录学生
    const stu = req.session.student ;
    // 若学生未登录则返回到登录页面并给出提示
    if( !stu ) {
        req.session.tip = { message: '请先登录' }
        resp.redirect('/student/sign/in');
        return;
    }
    
    // 从请求中获取通过表单提交的课程编号组成的数组
    // 采用 解构赋值 方式从 req.body 中获取 course 并重命名为 cids
    let { course: cids } = req.body ;
    cids = Array.isArray( cids ) ? cids : [ cids ? cids : -1 ] ;
    console.log( 'cids: ' , cids );

    // 查询当前已登录的学生返回一个 Student实例
    Student.findByPk( stu.id ).then( student => {
        let p1 = Promise.resolve( student );
        // 根据学生在页面上选择的课程编号查询课程信息
        let p2 = Course.findAll({
            where:{
                // where id in ( 1 , 2 , 3 )
                id: {
                    [Op.in]: cids
                }
            }
        });
        // Promise.all 的参数必须是 Array 、Map 、Set 等 iterable 类型的实例
        return Promise.all( [ p1 , p2 ] );
    }).then( values => {
        const student = values[0];
        let courses = values[1];
        return student.setCourses( courses );
    }).then( result => {
        console.log( result );
        resp.redirect('/student/choice');
    }).catch( reason => {
        // 暂时不考虑提示信息
        resp.redirect('/student/choose');
    });
});

// GET `/student/choice` 显示学生已经选择的课程列表
router.get('/student/choice',(req,resp)=>{
    const stu = req.session.student ;
    // 若学生未登录则返回到登录页面并给出提示
    if( !stu ) {
        req.session.tip = { message: '请先登录' }
        resp.redirect('/student/sign/in');
        return;
    }

    Student.findByPk( stu.id ).then( student => {
        return student.getCourses();
    }).then( courses => {
        courses = courses.map( c => { 
            let x = c.dataValues ;
            delete x.Score ;
            return x ;
        });
        resp.render( 'student/choice' , { courses , student: stu });
    }).catch( reason => {
        resp.render( 'student/choice' , { tip : { message: reason } });
    });
    
});


module.exports = router;